<template>
	<view :class="[`grid-gap-${props.gap}`, `grid-columns-${props.col * 2}`]" ref="xUploadsRef">
		<view class="images-item" :class="[props.type==='video'?`grid-column-${props.col * 2}`:'grid-column-2']" :style="{ height: props.type==='video'?`${height*2}px`:`${height}px` }" v-for="(temp, index) in tempList"
			:key="index">
			<image v-if="props.type === 'image'" :src="temp.url" mode="scaleToFill" class="bg rounded-4 w-100"
				:style="{ height: `${height}px` }" @tap="preview(index)" />
			<video v-else-if="props.type === 'video'" :src="temp.url" class="bg rounded-4 w-100"
				:style="{ height: `${height*2}px` }" />
			<view v-if="temp.error" class="error grid-gap-2">
				<text class="message h10">{{ temp.error }}</text>
				<text class="text-primary h10" @tap="upload(index)">重试</text>
			</view>
			<uni-icons type="spinner-cycle" color="var(--xl-grey)" size="38" class="loading"
				v-if="temp.loading"></uni-icons>
			<uni-icons type="closeempty" class="icons" color="var(--xl-danger-light-3)" v-if="!disbale"
				@tap="remove(index)"></uni-icons>
		</view>
		<slot :height="height">
			<view class="bg-dark-light-9 rounded-4 flex flex-center flex-column grid-gap-2"
				:style="{ height: `${height}px` }"
				:class="[tempList.length > 0 || !props.fill ? 'grid-column-2' : `grid-column-${props.col * 2}`]"
				@tap="selected" v-if="tempList.length < props.limit">
				<uni-icons :type="props.placeholderIcon" size="38" color="var(--xl-grey)"></uni-icons>
				<text class="text-grey h10">{{ props.placeholder }}</text>
				<text v-if="props.limit > 1" class="h10 font-weight-600 text-grey">
					{{ tempList.length }}/{{ props.limit }}
				</text>
			</view>
		</slot>
	</view>
</template>

<script setup lang="ts">
import { ref, watchEffect, defineProps, onMounted, nextTick } from 'vue';
import { $helper, $api } from '@/utils';
const props = withDefaults(defineProps<{
	modelValue: string | string[] | any[],
	type?: 'image' | 'video' | 'file'
	limit?: number
	col?: number
	gap?: number
	fill?: boolean
	autoUpload?: boolean
	data?: any
	margins?: number
	keyName?: string
	remove?: Function
	disbale?: boolean
	placeholder?: string
	placeholderIcon?: string
}>(), {
	limit: 1,
	type: 'image',
	col: 3,
	gap: 3,
	fill: false,
	autoUpload: true,
	margins: 0,
	data: {
		is_hide: 1
	},
	placeholder: '选择照片',
	placeholderIcon: 'images'
});
const tempList = ref<string[]>([]);
const height = ref(0);
const emit = defineEmits(['update:modelValue','change']);
watchEffect(() => {
	if (Array.isArray(props.modelValue)) {
		props.modelValue.forEach((item: string | any) => {
			if (typeof item === 'object') {
				if (tempList.value.find((temp: any) => temp.url === item[props.keyName])) return;
				tempList.value.push({
					...item,
					url: item[props.keyName],
					upload: true,
					loading: false,
					error: ''
				});
				return;
			} else {
				if (tempList.value.find((temp: any) => temp.url === item)) return;
				tempList.value.push({
					url: item,
					upload: true,
					loading: false,
					error: ''
				});
			}
		});
	} else {
		if (!props.modelValue || tempList.value.find((item: any) => item.url === props.modelValue)) return;
		tempList.value.push({
			url: props.modelValue,
			upload: true,
			loading: false,
			error: ''
		});
	}
});
const chooseImage = () => {
	$helper.chooseImage({
		count: props.limit,
		success: (res: any) => {
			res.tempFilePaths.forEach((item: string) => {
				if (tempList.value.includes(item) || tempList.value.length >= props.limit) return;
				tempList.value.push({
					url: item,
					upload: false,
					loading: false,
					error: ''
				});
			});
			if (props.autoUpload) {
				submit();
			}
		}
	});
}
const chooseVideo = () => {
	$helper.chooseVideo({
		maxDuration: 60,
		success: (res: any) => {
			if (tempList.value.includes(res.tempFilePath) || tempList.value.length >= props.limit) return;
			tempList.value.push({
				url: res.tempFilePath,
				upload: false,
				loading: false,
				error: ''
			});
			if (props.autoUpload) {
				submit();
			}
		}
	});
}
const chooseFile = () => {
	$helper.chooseFile({
		count: props.limit,
		success: (res: any) => {
			res.tempFiles.forEach((item: any) => {
				if (tempList.value.includes(item.path) || tempList.value.length >= props.limit) return;
				tempList.value.push({
					url: item.path,
					upload: false,
					loading: false,
					error: ''
				});
			});
			if (props.autoUpload) {
				submit();
			}
		}
	});
}
const selected = () => {
	if (props.disbale) return;
	switch (props.type) {
		case 'image':
			chooseImage();
			break;
		case 'video':
			chooseVideo();
			break;
		case 'file':
			chooseFile();
			break;
	}
}
const remove = (index: number) => {
	const item = tempList.value[index];
	if (props.remove) {
		props.remove(item, index).then(() => {
			tempList.value.splice(index, 1);
			if (item.upload) {
				update();
			}
		}).catch(() => {
		})
	} else {
		tempList.value.splice(index, 1);
		if (item.upload) {
			update();
		}
	}
}
const preview = (index: number) => {
	uni.previewImage({
		current: index,
		urls: tempList.value.map((item: any) => item.url)
	});
}
const upload = (i: number) => {
	const item = tempList.value[i];
	item.error = '';
	if (!item.upload) {
		item.loading = true;
		$api.Upload.upload({
			filePath: item.url,
			formData: props.data
		}).then((res: any) => {
			item.url = res.data.url;
			item.upload = true;
			update();
		}).catch((err: any) => {
			item.error = err.msg;
		}).finally(() => {
			item.loading = false;
		});
	}
}
const submit = () => {
	for (let i = 0; i < tempList.value.length; i++) {
		upload(i);
	}
}
const update = () => {
	const value = tempList.value.filter((item: any) => item.upload);
	if (value.length) {
		if (props.limit === 1) {
			if (props.keyName) {
				emit('update:modelValue', value[0]);
				emit('change', value[0]);
			} else {
				emit('update:modelValue', value[0]['url']);
				emit('change', value[0]['url']);
			}
		} else {
			if (props.keyName) {
				emit('update:modelValue', value);
				emit('change', value);
			} else {
				emit('update:modelValue', value.map((item: any) => item['url']));
				emit('change', value.map((item: any) => item['url']));
			}
		}
	} else {
		if (props.limit === 1) {
			emit('update:modelValue', '');
			emit('change');
		} else {
			emit('update:modelValue', []);
			emit('change');
		}
	}
}
const xUploadsRef = ref<HTMLElement>();
onMounted(() => {
	nextTick(() => {
		height.value = ($helper.info().windowWidth - props.margins - (4 * props.gap * (props.col - 1))) / props.col;
	});
});
defineExpose({
	submit,
	selected
});
</script>

<style lang="scss" scoped>
.images-item {
	position: relative;

	.icons {
		padding: 2px;
		position: absolute;
		right: -1px;
		top: -1px;
		background-color: $uni-bg-color-grey;
		border-bottom-left-radius: 8px;
		border-top-right-radius: 8px;
		z-index: 10;
	}

	.loading {
		position: absolute;
		right: 0;
		top: 0;
		left: 0;
		bottom: 0;
		background-color: var(--xl-white-mask);
		border-radius: 8px;
		z-index: 100;
		display: flex;
		justify-content: center;
		align-items: center;

		&:before,
		.uni-icons {
			animation: spinner-cycle 3s linear infinite;
		}
	}

	.error {
		position: absolute;
		top: 50%;
		left: 50%;
		max-width: 80%;
		background-color: var(--xl-mask);
		padding: 6px;
		border-radius: 8px;
		transform: translate(-50%, -50%);
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;

		.message {
			padding: 2px 4px;
			border-radius: 4px;
			color: var(--xl-white);
		}
	}
}

@keyframes spinner-cycle {
	0% {
		transform: rotate(0deg);
	}

	100% {
		transform: rotate(360deg);
	}
}
</style>